﻿using System.Net.Http.Headers;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;

namespace AIFast.Lakala
{
    public static class LakalaHelper
    {
        // 提取正则，形如 a="abc123",b="def456" 提取结果 abc123 , def456
        private readonly static Regex _signRegex = new(@"(\w+)\s*=\s*""([^""]*)""");

        public static HttpRequestMessage CreateSignedHttpRequest(string body, string url, LakalaOpenOptions options)
        {
            var tms = DateTimeOffset.Now.ToUnixTimeSeconds();
            var nonce = Guid.NewGuid().ToString("N")[..12];
            var sign = $"{options.AppId}\n{options.SerialNo}\n{tms}\n{nonce}\n{body}\n";

            var signedBytes = options.GetPriRsa().SignData(Encoding.UTF8.GetBytes(sign), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
            var signature = Convert.ToBase64String(signedBytes);

            var content = new StringContent(body, Encoding.UTF8, "application/json");
            var httpRequest = new HttpRequestMessage(HttpMethod.Post, url)
            {
                Content = content
            };

            httpRequest.Headers.Authorization =
                new AuthenticationHeaderValue("LKLAPI-SHA256withRSA", string.Join(
                    ',',
                    $"appid=\"{options.AppId}\"",
                    $"serial_no=\"{options.SerialNo}\"",
                    $"timestamp=\"{tms}\"",
                    $"nonce_str=\"{nonce}\"",
                    $"signature=\"{signature}\""));

            return httpRequest;
        }

        public static bool VerifyResponseSignature(HttpResponseHeaders headers, string body, LakalaOpenOptions options)
        {
            /*
             * Lklapi-Appid：原始送上来的Lklapi-Appid，异步交易结果通知无此字段
             * Lklapi-Serial：拉卡拉证书序列号
             * Lklapi-Timestamp：时间戳
             * Lklapi-Nonce：随机字符串
             * Lklapi-Signature：签名值
             * Lklapi-Traceid：供研发查询定位问题使用，建议打印出来 异步交易结果通知无此字段
             */

            var appid = headers.GetValues("Lklapi-Appid").Single();
            var serial = headers.GetValues("Lklapi-Serial").Single();
            var tms = headers.GetValues("Lklapi-Timestamp").Single();
            var nonce = headers.GetValues("Lklapi-Nonce").Single();
            var sig = headers.GetValues("Lklapi-Signature").Single();

            var sign = $"{appid}\n{serial}\n{tms}\n{nonce}\n{body}\n";

            return options.GetPubRsa().VerifyData(Encoding.UTF8.GetBytes(sign), Convert.FromBase64String(sig), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
        }

        public static bool VerifyRequestSignature(HttpRequestHeaders headers, string body, LakalaOpenOptions options)
        {
            /*
             *①认证方式：SHA256withRSA
             *②签名规则：产生签名值（signature）的签名串拼接一共有3行，每一行为一个参数，包括时间戳（timestamp）、随机数（nonce_str）、请求报文主体（body）。
             *行尾以\n（换行符，ASCII编码值为0x0A）结束，包括最后一行。如果参数本身以\n结束，也需要
             *加一个\n，测试环境公钥证书。注：不要用spring的注解接受（body）、验签前不要对通知内容（body）进行序列化与反序列化操作否则会导致验签失败。
             *③拼接方式：${timeStamp}\n+${nonceStr}\n+${body}\n
             */

            var auth = headers.Authorization;
            var paramer = auth.Parameter;

            return VerifyRequestSignature(paramer, body, options);
        }

        public static bool VerifyRequestSignature(string authParameter, string body, LakalaOpenOptions options)
        {
            var matches = _signRegex.Matches(authParameter);

            var tms = ReadValue("timestamp");
            var nonce = ReadValue("nonce_str");
            var sig = ReadValue("signature");

            var sign = $"{tms}\n{nonce}\n{body}\n";

            string ReadValue(string name)
            {
                var match = matches.First(d => d.Groups[1].Value == name);

                return match.Groups[2].Value;
            }

            return options.GetPubRsa().VerifyData(Encoding.UTF8.GetBytes(sign), Convert.FromBase64String(sig), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
        }
    }
}
